package com.itheima.wms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.pinda.exception.BizException;
import com.itheima.wms.common.enums.LocationFrozen;
import com.itheima.wms.common.enums.StockRecordType;
import com.itheima.wms.common.enums.StockRecordWay;
import com.itheima.wms.common.service.CrudServiceImpl;
import com.itheima.wms.dao.CheckListMapper;
import com.itheima.wms.dao.LocationMapper;
import com.itheima.wms.dao.StockRecordMapper;
import com.itheima.wms.dto.CheckListBatchDTO;
import com.itheima.wms.entity.*;
import com.itheima.wms.service.CheckListService;
import com.itheima.wms.service.CheckTaskService;
import com.itheima.wms.service.StockService;
import com.itheima.wms.vo.CheckListDetailVO;
import com.itheima.wms.vo.CheckListSumVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;


/**
 * <p>
 * 业务实现类
 * 盘点清单
 * </p>
 */
@Slf4j
@Service
public class CheckListServiceImpl extends CrudServiceImpl<CheckListMapper, CheckListEntity> implements CheckListService {

    @Autowired
    private StockService stockService;
    @Autowired
    private StockRecordMapper stockRecordMapper;
    @Autowired
    private CheckTaskService checkTaskService;
    @Autowired
    private LocationMapper locationMapper;

    @Override
    @Transactional
    public Boolean saveBatchByStockIds(CheckListBatchDTO checkListBatchDTO) {
        List<StockEntity> stockEntities = stockService.listByIds(checkListBatchDTO.getStockIds());
        List<CheckListEntity> checkListEntities = new ArrayList<>();
        for (StockEntity stockEntity : stockEntities) {
            CheckListEntity checklistEntity = CheckListEntity.builder().masterId(checkListBatchDTO.getMasterId()).stockId(stockEntity.getId()).stockNum(stockEntity.getFree()).status(1).build();
            checkListEntities.add(checklistEntity);

        }
        return this.saveBatch(checkListEntities);
    }

    @Override
    public boolean saveBatch(Collection<CheckListEntity> entityList) {
        boolean flag = super.saveBatch(entityList);
        // 冻结库存
        entityList.forEach(checkListEntity -> frozenStock(checkListEntity));
        return flag;
    }

    @Override
    public IPage<CheckListDetailVO> pageDetail(Page<CheckListDetailVO> page, Map data) {
        IPage<CheckListDetailVO> iPage = this.baseMapper.selectCheckListDetail(page, data);
        return iPage;
    }

    @Override
    public CheckListSumVO getSumByMasterId(Long masterId) {
        LambdaQueryWrapper<CheckListEntity> checkListWrapper = new LambdaQueryWrapper<>();
        checkListWrapper.eq(CheckListEntity::getMasterId, masterId);
        checkListWrapper.eq(CheckListEntity::getStatus, 1); // 查询一盘即可
        List<CheckListEntity> checkListEntities = this.baseMapper.selectList(checkListWrapper);
        return CheckListSumVO.builder().locationTotal(checkListEntities.size()).goodsTotal(checkListEntities.stream().mapToInt(CheckListEntity::getStockNum).sum()).build();
    }

    @Override
    public List<Long> stockIds(Map data) {
        LambdaQueryWrapper<CheckListEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(CheckListEntity::getStockId);
        wrapper.eq(CheckListEntity::getMasterId, data.get("masterId"));
        List ids = this.baseMapper.selectObjs(wrapper);
        return ids;
    }

    @Override
    public void cancelBatch(List<CheckListEntity> checkListEntities) {
        checkListEntities.forEach(checkListEntity -> unfreezeStock(checkListEntity));
    }

    @Override
    @Transactional
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        idList.forEach(id -> unfreezeStock(this.getById(id)));
        return super.removeByIds(idList);
    }

    @Override
    @Transactional
    public boolean updateById(CheckListEntity entity) {
        CheckListEntity dbEntity = this.getById(entity.getId());
        if (null != entity.getCheckNum()) {
            entity.setDifferenceNum(entity.getCheckNum() - dbEntity.getStockNum());
        }
        boolean result = super.updateById(entity);
        dbEntity = this.getById(entity.getId());

        // 实盘数量
        if (null != entity.getCheckNum()) {
            QueryWrapper<CheckListEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("IFNULL(sum(check_num),0) as totalNum,IFNULL(sum(abs(difference_num)),0) as differenceNum")
                    .eq("master_id", dbEntity.getMasterId())
                    .eq("status", dbEntity.getStatus());

            Map<String, Object> map = this.baseMapper.selectMaps(queryWrapper).get(0);
            Integer totalNum = ((java.math.BigDecimal) map.get("totalNum")).intValue();
            Integer differenceNum = ((java.math.BigDecimal) map.get("differenceNum")).intValue();

            LambdaQueryWrapper<CheckTaskEntity> updateWrapper = new LambdaQueryWrapper<>();
            updateWrapper.eq(CheckTaskEntity::getMasterId, dbEntity.getMasterId());
            updateWrapper.eq(CheckTaskEntity::getCheckNum, dbEntity.getStatus());
            checkTaskService.update(CheckTaskEntity.builder().checkTotal(totalNum).differenceNum(differenceNum).build(), updateWrapper);
        }

        return result;
    }

    /**
     * 冻结库存
     *
     * @param entity
     */
    private void frozenStock(CheckListEntity entity) {
        Long stockId = entity.getStockId();
        Integer stockNum = entity.getStockNum();

        StockEntity stockEntity = stockService.getById(stockId);
        locationMapper.updateById(LocationEntity.builder().id(stockEntity.getLocationId()).frozen(LocationFrozen.FROZEN.getCode()).build());

        Integer original = stockEntity.getTotal();
        Integer originalFree = stockEntity.getFree();

        if (stockNum == null || stockNum == 0) {
            throw new BizException("库位没有可盘点的库存");
        }

        stockService.frozen(stockId, stockNum);

        StockRecordEntity stockRecordEntity = new StockRecordEntity();
        stockRecordEntity.setSourceId(entity.getId());
        stockRecordEntity.setLocationId(stockEntity.getLocationId());
        stockRecordEntity.setType(StockRecordType.PD.getCode());// 类型盘点
        stockRecordEntity.setOriginal(original);
        stockRecordEntity.setOriginalFree(originalFree);
        stockRecordEntity.setWay(StockRecordWay.FROZEN.getCode());
        stockRecordEntity.setAlteration(stockNum);
        stockRecordEntity.setResult(original);
        stockRecordEntity.setResultFree(originalFree - stockNum);
        stockRecordMapper.insert(stockRecordEntity);
    }

    /**
     * 解冻库存
     *
     * @param entity
     */
    private void unfreezeStock(CheckListEntity entity) {
        Long stockId = entity.getStockId();
        Integer stockNum = entity.getStockNum();

        StockEntity stockEntity = stockService.getById(stockId);
        locationMapper.updateById(LocationEntity.builder().id(stockEntity.getLocationId()).frozen(LocationFrozen.NORMAL.getCode()).build());
        Integer original = stockEntity.getTotal();
        Integer originalFree = stockEntity.getFree();

        stockService.unfreeze(stockId, stockNum);

        StockRecordEntity stockRecordEntity = new StockRecordEntity();
        stockRecordEntity.setSourceId(entity.getId());
        stockRecordEntity.setLocationId(stockEntity.getLocationId());
        stockRecordEntity.setType(StockRecordType.PD.getCode());// 类型盘点
        stockRecordEntity.setOriginal(original);
        stockRecordEntity.setOriginalFree(originalFree);
        stockRecordEntity.setWay(StockRecordWay.UNFREEZE.getCode());
        stockRecordEntity.setAlteration(stockNum);
        stockRecordEntity.setResult(original);
        stockRecordEntity.setResultFree(originalFree + stockNum);
        stockRecordMapper.insert(stockRecordEntity);
    }
}


